#include <vector>
#include <string>
#include <fstream>
#include <iostream>

class Student
{
public:
    Student(const std::string &name,int id,int grade)
        :_name(name),_id(id),_grade(grade)
    {}

    Student(std::string &&name,int id,int grade)
        :_name(std::move(name)),_id(id),_grade(grade)
    {}

    std::string _name;
    int _id;
    int _grade;
};

class HashNode
{
public:
    std::pair<int,Student *> _kv;
    HashNode *_next;
    HashNode(const std::pair<int,Student *> kv)
        :_kv(kv),_next(nullptr)
    {}
};

class HashCode// 哈希函数
{
public:
    int operator()(int val)
    {
        return (val % 10);// 获得个位
    }
};

class HashMap
{
    typedef HashNode Node;
public:
    HashMap()
        :_tables(10)
    {}

    ~HashMap()
    {
        for(int i=0;i<_tables.size();i++)
        {
            Node *cur = _tables[i];
            Node *next = nullptr;
            while(cur)
            {
                next = cur->_next;
                delete cur;
                cur = nullptr;
                cur = next;
            }
        }
    }

    Student *Get(int id)
    {
        HashCode hashcode;
        int pos = hashcode(id) % _tables.size();
        Node *cur = _tables[pos];
        while(cur)
        {
            if(hashcode(id) == cur->_kv.first) return cur->_kv.second;
            cur = cur->_next;
        }
        return nullptr;
    }

    bool Put(Student *stu)
    {
        if(stu == nullptr) return false;// 插入失败
        if(_n*10 / _tables.size() == 10)// 需要扩容
        {
            HashMap newtable;
            newtable._tables.resize(_tables.size() * 2);// 扩容到当前的2倍
            for(int i=0;i<_tables.size();i++)
            {
                Node *cur = _tables[i];
                Node *next = nullptr;
                while(cur)
                {
                    next = cur->_next;
                    newtable.Put(cur->_kv.second);// 重新插入到新的哈希表中
                    cur = next;
                }
            }
            _tables = std::move(newtable._tables);// 交换
        }
        HashCode hashcode;
        int pos = hashcode(stu->_id) % _tables.size();
        // 头插
        Node *newnode = new Node(std::make_pair(pos,stu));
        newnode->_next = _tables[pos];// 先指向当前头节点
        _tables[pos] = newnode;// 做头
        ++_n;// 增加有效数据
        return true;// 插入成功
    }
private:
    std::vector<Node *> _tables;// 哈希表
    size_t _n;// 有效数据个数
};

// 字符串解析工作
void Split(const std::string &src,const std::string &sep,std::vector<std::string> *out)
{
    int begin = 0,pos = 0;
    while(begin < src.size())
    {
        pos = src.find(sep,begin);
        if(pos == std::string::npos)
        {
            out->push_back(src.substr(begin));
            break;
        }
        if(pos == begin)
        {
            begin += sep.size();
            continue;
        }
        out->push_back(src.substr(begin,pos - begin));
        begin = pos;
    }
}

const static std::string filename = "Students.txt";
bool Read(std::vector<std::string> *out)// 从文件读取数据
{
    std::ifstream in(filename);
    if(!in.is_open()) return false;// 读取失败返回false
    char buffer[1024] = {0};
    while(in.getline(buffer,sizeof(buffer)))// 按行读
    {
        out->push_back(buffer);// 结果保存在结果集当中
    }
    in.close();
    return true;
}

void MakeStudent(const std::vector<std::string> &v,HashMap &hash)// 构造出Student对象并放入HashMap
{
    std::string name = v[0];
    int id = std::stoi(v[1]);
    int grade = std::stoi(v[2]);
    Student *stu = new Student(std::move(name),id,grade);// new一个Student对象
    hash.Put(stu);// 放入哈希表中
}

int main()
{
    HashMap hash;
    std::vector<std::string> filedata;
    Read(&filedata);// 读取数据放到vector当中
    for(auto &e:filedata)
    {
        std::vector<std::string> studata;
        Split(e,",",&studata);// 将构造Student类所需的数据解析出来
        MakeStudent(studata,hash);
    }

    while(true)
    {
        int id;
        std::cout << "请输出想要查询的学生学号>>";
        std::cin >> id;
        Student *stu = hash.Get(id);
        if(stu == nullptr)
        {
            std::cout << "该学号对应的学生不存在!" << std::endl;
            continue;
        }
        std::cout << "姓名:" << stu->_name << " 学号:" << stu->_id << " 成绩:" << stu->_grade << std::endl;
    }
    return 0;
}